#ifndef _SERIAL_H_
#define _SERIAL_H_

#include "device.h"
#include "stdbool.h"

#ifdef __cplusplus
extern "C" {
#endif

#define SERIAL_BUFFER_LENGTH            1280
#define SERIAL_DMA_RX_BUFFER_LENGTH     64
#define SERIAL_DMA_TX_BUFFER_LENGTH     128

#define DATA_BITS_5                     5
#define DATA_BITS_6                     6
#define DATA_BITS_7                     7
#define DATA_BITS_8                     8
#define DATA_BITS_9                     9

#define STOP_BITS_1                     0
#define STOP_BITS_2                     1
#define STOP_BITS_3                     2
#define STOP_BITS_4                     3

#define PARITY_NONE                     0
#define PARITY_ODD                      1
#define PARITY_EVEN                     2

#define BIT_ORDER_LSB                   0
#define BIT_ORDER_MSB                   1

#define NRZ_NORMAL                      0       /* Non Return to Zero : normal mode */
#define NRZ_INVERTED                    1       /* Non Return to Zero : inverted mode */

#define SERIAL_INT_TXDONE     			(uint8_t)0x01
#define SERIAL_INT_RXDONE 				(uint8_t)0x02
#define SERIAL_INT_DMATXDONE			(uint8_t)0x03
#define SERIAL_INT_DMARXDONE			(uint8_t)0x04
#define SERIAL_INT_IDLE			        (uint8_t)0x05

struct serial_buffer_s
{
	volatile  int32_t   head;   /* Index to the head [IN] index in the buffer */
	volatile  int32_t   tail;   /* Index to the tail [OUT] index in the buffer */
	int32_t             size;   /* The allocated size of the buffer */
	unsigned char       buffer[SERIAL_BUFFER_LENGTH]; /* Pointer to the allocated buffer memory */
};

struct lt_serial_cfg_s
{
	int32_t buad_rate                 ;
    int32_t data_bits               :4;
    int32_t stop_bits               :2;
    int32_t parity                  :2;
    int32_t bit_order               :1;
    int32_t invert                  :1;
	int32_t bufsz					:16;
    int32_t reserved                :4;
};

extern struct lt_serial_cfg_s serial_default_cfg;

struct lt_serial_s
{
	struct   lt_dev_s dev;
#ifdef CONFIG_SERIAL_TERMIOS
	/* Terminal control flags */

	tcflag_t             tc_iflag;     /* Input modes */
	tcflag_t             tc_oflag;     /* Output modes */
	tcflag_t             tc_lflag;     /* Local modes */
#endif
	//sem_t        tx_done_sem;
	bool    tx_done;


	struct serial_buffer_s recv_buffer;
	struct serial_buffer_s send_buffer;
    
    uint8_t  dma_rx_buffer[SERIAL_DMA_RX_BUFFER_LENGTH];
    uint8_t  dma_tx_buffer[SERIAL_DMA_TX_BUFFER_LENGTH];

	
	int32_t (*init)(struct lt_serial_s *serial);
	int32_t (*deinit)(struct lt_serial_s *serial);
    int32_t (*configure)(struct lt_serial_s *serial,struct lt_serial_cfg_s *cfg);

	/* for poll */
    int32_t (*putc)(struct lt_serial_s *serial, unsigned char ch);
    int32_t (*getc)(struct lt_serial_s *serial, unsigned char *ch);

	/* for dma */
    int32_t  (*dma_tx_start)(struct lt_serial_s *serial, int32_t size);
    
    void     (*dma_tx_init)(struct lt_serial_s *serial);
	void     (*dma_tx_deinit)(struct lt_serial_s *serial);
    void     (*dma_tx_disable)(struct lt_serial_s *serial);
    

	void     (*dma_rx_init)(struct lt_serial_s *serial);
	void     (*dma_rx_deinit)(struct lt_serial_s *serial);
    int32_t  (*dma_rx_get_data_length)(struct lt_serial_s *serial);
	int32_t   dma_read_ptr;
    
	struct lt_serial_cfg_s cfg;
	
	/* for irq */
	void (*enable_irq)(struct lt_serial_s *serial,int32_t irq);
	void (*disable_irq)(struct lt_serial_s *serial,int32_t irq);
	void *priv;         /* Used by the arch-specific logic */
};

void     serial_buffer_init(struct serial_buffer_s *buffer);
int32_t  serial_buffer_put(struct serial_buffer_s *buffer,unsigned char *ch,int32_t size);
int32_t  serial_buffer_get(struct serial_buffer_s *buffer,unsigned char *ch,int32_t size);

void     serial_device_register(struct lt_serial_s *serial,char *name,uint16_t flag);
void     serial_device_unregister(struct lt_serial_s *serial,char *name,uint16_t flag);

void     serial_isr(struct lt_serial_s *serial,int32_t event);

#ifdef __cplusplus
}
#endif

#endif
